package com.kai.service.problem.facade;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.kai.service.data.request.problem.*;
import com.kai.service.data.response.problem.CountUserProblemResponse;
import com.kai.service.data.response.problem.ProblemReplyResponse;
import com.kai.service.data.response.problem.ProblemResponse;
import com.kai.service.data.response.user.UserInfoResponse;
import com.kai.service.enums.ArticleOperateTypeEnum;
import com.kai.service.enums.ResultCodeEnum;
import com.kai.service.exception.GenericException;
import com.kai.service.problem.entity.Problem;
import com.kai.service.problem.entity.ProblemOperatorRecord;
import com.kai.service.problem.entity.ProblemReply;
import com.kai.service.problem.mapper.ProblemReplyMapper;
import com.kai.service.problem.service.IProblemOperatorRecordService;
import com.kai.service.problem.service.IProblemReplyService;
import com.kai.service.problem.service.IProblemService;
import com.kai.service.user.entity.User;
import com.kai.service.user.service.IUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

@Service
public class ProblemFacade {

    @Autowired
    private IProblemService problemService;

    @Autowired
    private IProblemOperatorRecordService problemOperatorRecordService;

    @Autowired
    private IProblemReplyService problemReplyService;

    @Resource
    private ProblemReplyMapper problemReplyMapper;

    @Autowired
    private IUserService userService;

    /**
     * 创建问题
     *
     * @param createProblemRequest
     * @return
     */
    public Boolean createProblem(CreateProblemRequest createProblemRequest) {
        Date nowDate = new Date();
        Problem problem = new Problem();
        BeanUtil.copyProperties(createProblemRequest, problem);
        problem.setCreateDatetime(nowDate).setUpdateDatetime(nowDate);

        return problemService.save(problem);
    }

    /**
     * 分页查询问题
     *
     * @param pagingProblemRequest
     * @return
     */
    public IPage<ProblemResponse> pagingProblem(PagingProblemRequest pagingProblemRequest) {
        Long userId = pagingProblemRequest.getUserId();
        Long proposeId = pagingProblemRequest.getProposeId();
        IPage<Problem> problemIPage = problemService.page(new Page<>(pagingProblemRequest.getPageIndex(), pagingProblemRequest.getPageSize()), new LambdaQueryWrapper<Problem>()
                .eq(Objects.nonNull(proposeId), Problem::getProposeId, proposeId)
                .orderByDesc(Problem::getCreateDatetime));

        List<ProblemResponse> problemResponseList = problemIPage.getRecords().stream().map(problem -> getProblemInfo(problem, userId)).collect(Collectors.toList());

        IPage<ProblemResponse> problemResponseIPage = new Page<>();
        problemResponseIPage.setRecords(problemResponseList);
        problemResponseIPage.setCurrent(problemIPage.getCurrent());
        problemResponseIPage.setPages(problemIPage.getPages());
        problemResponseIPage.setSize(problemIPage.getSize());
        problemResponseIPage.setTotal(problemIPage.getTotal());

        return problemResponseIPage;
    }

    /**
     * 查询热门问题列表
     *
     * @return
     */
    public List<ProblemResponse> hotProblemList(Long userId) {
        List<Integer> hotProblemIds = problemReplyMapper.getHotProblemIds();

        return hotProblemIds.stream().map(problemId -> {
            Problem problem = problemService.getById(problemId);

            return getProblemInfo(problem, userId);
        }).collect(Collectors.toList());
    }

    /**
     * 获取问题信息
     *
     * @param problem
     * @param userId
     * @return
     */
    private ProblemResponse getProblemInfo(Problem problem, Long userId){
        ProblemResponse problemResponse = new ProblemResponse();
        BeanUtil.copyProperties(problem, problemResponse);
        // 点赞数量
        int like = problemOperatorRecordService.count(new LambdaQueryWrapper<ProblemOperatorRecord>()
                .eq(ProblemOperatorRecord::getReferenceId, problem.getId())
                .eq(ProblemOperatorRecord::getType, "PROBLEM")
                .eq(ProblemOperatorRecord::getCategory, "LIKE"));
        problemResponse.setLike(like);

        // 当前用户是否点赞
        if (Objects.nonNull(userId)) {
            List<String> list = problemOperatorRecordService.list(new LambdaQueryWrapper<ProblemOperatorRecord>()
                            .eq(ProblemOperatorRecord::getOperatorId, userId)
                            .eq(ProblemOperatorRecord::getType, "PROBLEM"))
                    .stream().map(ProblemOperatorRecord::getCategory).collect(Collectors.toList());
            if (list.contains(ArticleOperateTypeEnum.LIKE.name())) {
                problemResponse.setIsLike(Boolean.TRUE);
            }
        }

        // 问题提出者信息
        UserInfoResponse userInfo = userService.getUserInfo(problem.getProposeId());
        problemResponse.setProposeInfo(userInfo);

        return problemResponse;
    }

    /**
     * 修改问题
     *
     * @param problemId
     * @param updateProblemRequest
     * @return
     */
    public Boolean updateProblem(Integer problemId, UpdateProblemRequest updateProblemRequest) {
        Problem problem = problemService.getById(problemId);
        if (Objects.isNull(problem)){
            throw new GenericException(ResultCodeEnum.PROBLEM_NOT_EXIST);
        }
        BeanUtil.copyProperties(updateProblemRequest, problem);
        problem.setId(problemId).setUpdateDatetime(new Date());

        return problemService.updateById(problem);
    }

    /**
     * 删除问题
     *
     * @param problemId
     * @return
     */
    @Transactional(rollbackFor = Throwable.class)
    public Boolean deleteProblem(Integer problemId) {
        problemService.removeById(problemId);
        List<Integer> list = problemReplyService.list(new LambdaQueryWrapper<ProblemReply>().eq(ProblemReply::getProblemId, problemId)).stream().map(ProblemReply::getProblemId).collect(Collectors.toList());
        if (!CollectionUtils.isEmpty(list)){
            problemReplyService.removeByIds(list);
        }
        list.add(problemId);
        problemOperatorRecordService.remove(new LambdaQueryWrapper<ProblemOperatorRecord>().in(ProblemOperatorRecord::getReferenceId, list));

        return Boolean.TRUE;
    }

    /**
     * 回答问题
     *
     * @param problemId
     * @param replyProblemRequest
     * @return
     */
    @Transactional(rollbackFor = Throwable.class)
    public Boolean replyProblem(Integer problemId, ReplyProblemRequest replyProblemRequest) {
        Date nowDate = new Date();
        Problem problem = problemService.getById(problemId);
        if (Objects.isNull(problem)){
            throw new GenericException(ResultCodeEnum.PROBLEM_NOT_EXIST);
        }
        ProblemReply problemReply = new ProblemReply();
        BeanUtil.copyProperties(replyProblemRequest, problemReply);
        problemReply.setProblemId(problemId).setCreateDatetime(nowDate).setUpdateDatetime(nowDate);

        return problemReplyService.save(problemReply);
    }

    /**
     * 分页查询问题回复
     *
     * @param problemId
     * @param pagingProblemReplyRequest
     * @return
     */
    public IPage<ProblemReplyResponse> pagingProblemReply(Long problemId, PagingProblemReplyRequest pagingProblemReplyRequest) {
        Integer replyId = pagingProblemReplyRequest.getReplyId();
        Long userId = pagingProblemReplyRequest.getUserId();
        IPage<ProblemReply> problemReplyIPage = problemReplyService.page(new Page<>(pagingProblemReplyRequest.getPageIndex(), pagingProblemReplyRequest.getPageSize()), new LambdaQueryWrapper<ProblemReply>()
                .eq(ProblemReply::getProblemId, problemId)
                .eq(Objects.nonNull(replyId), ProblemReply::getProblemReplyId, replyId)
                .orderByDesc(ProblemReply::getCreateDatetime));

        List<ProblemReplyResponse> problemReplyResponseList = problemReplyIPage.getRecords().stream().map(problemReply -> {
            ProblemReplyResponse problemReplyResponse = new ProblemReplyResponse();
            BeanUtil.copyProperties(problemReply, problemReplyResponse);
            Integer problemReplyId = problemReply.getId();

            // 查询回答人信息
            User responderUser = userService.getById(problemReply.getResponderId());
            problemReplyResponse.setResponderNickName(responderUser.getNickName());
            problemReplyResponse.setResponderImgUrl(responderUser.getImgUrl());

            // 查询接收回答人信息
            if (!Objects.equals(-1L, problemReply.getRecipientId())){
                User toUser = userService.getById(problemReply.getRecipientId());
                problemReplyResponse.setRecipientNickName(toUser.getNickName());
                problemReplyResponse.setRecipientImgUrl(toUser.getImgUrl());
            }else {
                // 查询子评论条数
                int count = problemReplyService.count(new LambdaQueryWrapper<ProblemReply>().eq(ProblemReply::getProblemReplyId, problemReply.getId()));
                problemReplyResponse.setSubNumber(count);
            }

            int like = problemOperatorRecordService.count(new LambdaQueryWrapper<ProblemOperatorRecord>()
                    .eq(ProblemOperatorRecord::getReferenceId, problemReplyId)
                    .eq(ProblemOperatorRecord::getType, "REPLY")
                    .eq(ProblemOperatorRecord::getCategory, "LIKE"));
            problemReplyResponse.setLike(like);

            // 当前用户是否点赞此评论
            ProblemOperatorRecord problemOperatorRecord = problemOperatorRecordService.getOne(new LambdaQueryWrapper<ProblemOperatorRecord>()
                    .eq(ProblemOperatorRecord::getOperatorId, userId)
                    .eq(ProblemOperatorRecord::getReferenceId, problemReply.getId())
                    .eq(ProblemOperatorRecord::getType, "REPLY")
                    .eq(ProblemOperatorRecord::getCategory, "LIKE"));
            if (null != problemOperatorRecord){
                problemReplyResponse.setIsLike(Boolean.TRUE);
            }

            return problemReplyResponse;
        }).collect(Collectors.toList());

        IPage<ProblemReplyResponse> problemReplyResponseIPage = new Page<>();
        problemReplyResponseIPage.setRecords(problemReplyResponseList);
        problemReplyResponseIPage.setPages(problemReplyIPage.getPages());
        problemReplyResponseIPage.setCurrent(problemReplyIPage.getCurrent());
        problemReplyResponseIPage.setTotal(problemReplyIPage.getTotal());

        return problemReplyResponseIPage;
    }

    /**
     * 问题操作，点赞等
     *
     * @param problemOperatorRecordRequest
     * @return
     */
    public Boolean operatorProblem(ProblemOperatorRecordRequest problemOperatorRecordRequest) {
        ProblemOperatorRecord problemOperatorRecord = new ProblemOperatorRecord();
        BeanUtil.copyProperties(problemOperatorRecordRequest, problemOperatorRecord);
        problemOperatorRecord.setCreateDatetime(new Date());

        return problemOperatorRecordService.save(problemOperatorRecord);
    }

    /**
     * 删除回答
     *
     * @param replyId
     * @return
     */
    public Boolean deleteReply(Integer replyId) {
        problemReplyService.removeById(replyId);
        problemOperatorRecordService.remove(new LambdaQueryWrapper<ProblemOperatorRecord>()
                .eq(ProblemOperatorRecord::getReferenceId, replyId)
                .eq(ProblemOperatorRecord::getType, "REPLY"));

        return Boolean.TRUE;
    }

    /**
     * 统计用户提问数量
     *
     * @param userId
     * @return
     */
    public CountUserProblemResponse countProblem(Long userId) {
        int problemCount = problemService.count(new LambdaQueryWrapper<Problem>().eq(Problem::getProposeId, userId));
        int replyCount = problemReplyService.count(new LambdaQueryWrapper<ProblemReply>().eq(ProblemReply::getResponderId, userId));

        CountUserProblemResponse countUserProblemResponse = new CountUserProblemResponse();
        countUserProblemResponse.setProblemCount(problemCount);
        countUserProblemResponse.setReplyCount(replyCount);

        return countUserProblemResponse;
    }
}
